using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.UI;

namespace BlockOS.Client.GUI
{
    [ExecuteAlways]
    public class TerminalInterface : UIBehaviour
    {
        private RectTransform m_rectTransform;
        public RectTransform rectTransform
        {
            get
            {
                if (m_rectTransform == null) m_rectTransform = GetComponent<RectTransform>();
                return m_rectTransform;
            }
        }

        public RectTransform canvasRect;
        public GameObject terminalContent;
        public InputField terminalInput;
        public Button showButton, submitButton, closeButton;
        public Text messagePanel;

        public InputAction showAction;
        public InputAction closeAction;
        public InputAction submitAction;
        public InputAction copyAction;
        public InputAction undoAction;

        [Space]
        public AnimationCurve showCurve;
        public float showTime;
        public AnimationCurve closeCurve;
        public float closeTime;

        [Space]
        public UnityEvent<string> onCommandInput;

        private List<string> cmdRecord = new();
        private int prevPtr = 0;

        protected override void Awake()
        {
            closeAction.performed += ctx => Close();
            submitAction.performed += ctx => { if (!terminalInput.isFocused) OnSumbitButton(); };
            showAction.performed += c => Show();
            copyAction.performed += c => CopyPrevInput();
            undoAction.performed += c => UndoCopyInput();
        }

        protected override void OnEnable()
        {
            ResetControls();
            EnableEntry();
        }

        public void AddMessage(string msg)
        {
            messagePanel.text += msg + "\n";
        }

        public void ClearMessagePanel()
        {
            messagePanel.text = string.Empty;
        }

        public void OnTextSubmit(string cmd)
        {
            if (cmd == string.Empty) return;
            onCommandInput?.Invoke(cmd);
            cmdRecord.Add(cmd);
            prevPtr = cmdRecord.Count - 1;
            terminalInput.text = "";
            terminalInput.ActivateInputField();
        }

        public void OnSumbitButton()
        {
            OnTextSubmit(terminalInput.text);
        }

        public void Show()
        {
            terminalContent.SetActive(true);

            DisableAll();

            StartCoroutine(PlayShowAnim(showTime));
        }

        public IEnumerator PlayShowAnim(float time)
        {
            var targetY = 0.0f;
            var startPosition = rectTransform.anchoredPosition;
            var currentPosition = startPosition;
            var t = 0f;
            while (!Mathf.Approximately(currentPosition.y, targetY))
            {
                currentPosition.y = Mathf.Lerp(startPosition.y, targetY, showCurve.Evaluate(t / time));

                rectTransform.anchoredPosition = currentPosition;

                t += Time.deltaTime;
                yield return null;
            }

            currentPosition.y = 0;
            rectTransform.anchoredPosition = currentPosition;
            EnableTerminal();
            terminalInput.ActivateInputField();

            DisableEntry();

            yield return null;
        }

        public void Close()
        {
            showButton.gameObject.SetActive(true);
            DisableAll();

            StartCoroutine(PlayCloseAnim(closeTime));
        }

        public IEnumerator PlayCloseAnim(float time)
        {
            var targetY = canvasRect.sizeDelta.y;
            var startPosition = rectTransform.anchoredPosition;
            var currentPosition = startPosition;
            var t = 0f;
            while (!Mathf.Approximately(currentPosition.y, targetY))
            {
                currentPosition.y = Mathf.Lerp(startPosition.y, targetY, closeCurve.Evaluate(t / time));

                rectTransform.anchoredPosition = currentPosition;

                t += Time.deltaTime;
                yield return null;
            }

            currentPosition.y = targetY;
            rectTransform.anchoredPosition = currentPosition;

            EnableEntry();
            ResetControls();

            yield return null;
        }

        public void CopyPrevInput()
        {
            if (cmdRecord.Count == 0) return;

            terminalInput.text = cmdRecord[prevPtr];
            prevPtr -= 1;
            if (prevPtr < 0) prevPtr = 0;
        }

        public void UndoCopyInput()
        {
            if (cmdRecord.Count == 0) return;

            prevPtr = (prevPtr + 1 >= cmdRecord.Count) ? cmdRecord.Count - 1 : prevPtr + 1;
            terminalInput.text = cmdRecord[prevPtr];
        }

        public void ResetControls()
        {
            ClearMessagePanel();
            terminalContent.SetActive(false);

            undoAction.Disable();
            copyAction.Disable();
            submitAction.Disable();
            closeAction.Disable();
        }

        public void DisableAll()
        {
            terminalInput.interactable = false;
            showButton.interactable = false;
            submitButton.interactable = false;
            closeButton.interactable = false;
        }

        public void EnableTerminal()
        {
            terminalInput.interactable = true;
            submitButton.interactable = true;
            closeButton.interactable = true;

            undoAction.Enable();
            copyAction.Enable();
            submitAction.Enable();
            closeAction.Enable();
        }

        public void EnableEntry()
        {
            showButton.gameObject.SetActive(true);
            showButton.interactable = true;
            showAction.Enable();
        }

        public void DisableEntry()
        {
            showButton.gameObject.SetActive(false);
            showButton.interactable = false;
            showAction.Disable();
        }
    }
}
